home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
-
- /*
- * hrq.c provides two entry points; host_responds_quickly() and hrqerr().
- *
- * host_responds_quickly sends an ICMP echo request to the remote host
- * whose name is the only parameter to the function. It sets a very
- * short timer, and reports whether the remote host sends an ICMP echo
- * reply before the timer expires. host_responds_quickly can be
- * incorporated into a program similar to a no-frills version of ping,
- * but one in which the timeout period is mercifully brief.
- *
- * hrqerr translates integer error codes from host_responds_quickly into
- * human readable strings.
- *
- * Author: Aaron Schuman
- */
-
- #include <stdio.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/signal.h>
- #include <sys/socket.h>
- #include <netinet/in_systm.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #include <netinet/ip_icmp.h>
- #include <netdb.h>
- #include "hrq.h"
-
- #define FALSE 0
- #define TRUE 1
-
- static int timer_expired = FALSE;
-
-
- static void
- acknowledge_alarm()
- {
- timer_expired = TRUE;
- }
-
-
- int
- host_responds_quickly( char * hostname )
- {
- struct hostent * host_p;
- struct sockaddr address_buffer;
- struct sockaddr_in * dst_address =
- (struct sockaddr_in *) &address_buffer;
- uid_t my_uid;
- uid_t my_euid;
- struct protoent * protocol;
- int sockfd;
- const int data_length = 56;
- const int max_ip = 60;
- const int max_icmp = 76;
- const int packet_size = data_length + max_ip + max_icmp;
- u_char * packet;
- struct icmp * icmp_p;
- u_char packet_buffer[packet_size];
- int unique_identifier;
- int length;
- int remaining_bytes = data_length + 8;
- u_short * current_bytes;
- int checksum = 0;
- struct itimerval newtimer;
- struct itimerval oldtimer;
- int max_length;
- struct sockaddr_in src_address;
-
- /* translate host name to host address */
- host_p = gethostbyname( hostname );
- if ( !host_p )
- return (( HOST_NOT_FOUND == h_errno )
- ? HRQERR_UNKNOWNHOST : HRQERR_GETHOSTBYNAME );
- dst_address->sin_family = host_p->h_addrtype;
- bcopy( host_p->h_addr, (caddr_t)&dst_address->sin_addr,
- host_p->h_length );
-
- /* acquire privilege */
- my_uid = getuid();
- my_euid = geteuid();
- if ( 0 > setreuid( my_uid, my_euid ))
- return HRQERR_SETREUID;
-
- /* obtain memory resources */
- if ((protocol = getprotobyname("icmp")) == NULL)
- return HRQERR_GETPROTOBYNAME;
- if ((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0)
- return HRQERR_SOCKET;
- if( (packet = (u_char *)malloc((unsigned)packet_size)) == NULL )
- return HRQERR_MALLOC;
-
- /* send ICMP echo request */
- icmp_p = (struct icmp *)packet_buffer;
- icmp_p->icmp_type = ICMP_ECHO;
- icmp_p->icmp_code = 0;
- icmp_p->icmp_cksum = 0;
- icmp_p->icmp_seq = 0;
- icmp_p->icmp_id = unique_identifier = getpid() & 0xFFFF;
- length = data_length + 8; /* skip ICMP header */
-
- /* determine packet checksum */
- current_bytes = (u_short *) icmp_p;
- while (( remaining_bytes -= 2) > -1 )
- checksum += *current_bytes++;
- if ( remaining_bytes == 1 )
- checksum += *(u_char *) current_bytes ;
- checksum = ( checksum >> 16 ) + ( checksum & 0xffff );
- checksum += ( checksum >> 16 );
- icmp_p->icmp_cksum = ~checksum;
-
- (void) sendto( sockfd, (char *)packet_buffer, length, 0,
- &address_buffer, sizeof(struct sockaddr) );
-
- /* set alarm */
- newtimer.it_value.tv_sec = 0;
- newtimer.it_value.tv_usec = 1000;
- newtimer.it_interval.tv_sec = 1;
- newtimer.it_interval.tv_usec = 1000;
- signal( SIGALRM, acknowledge_alarm );
- if (0 > setitimer(ITIMER_REAL, &newtimer, &oldtimer))
- return HRQERR_SETITIMER;
-
- /* receive ICMP echo reply */
- (void) setreuid( my_euid, my_uid );
- while ( !timer_expired )
- {
- max_length = sizeof( src_address );
- length = recvfrom( sockfd, (char *)packet, packet_size,
- 0, (struct sockaddr *)&src_address, &max_length );
- if ( length < 0 ) /* probably EINTR */
- return TARDY_RESPONSE;
- icmp_p = (struct icmp *)
- ( packet + (((struct ip *) packet)->ip_hl << 2 ));
- if (( icmp_p->icmp_type != ICMP_ECHOREPLY ) ||
- ( icmp_p->icmp_id != unique_identifier ))
- continue;
- return QUICK_RESPONSE;
- }
- }
-
-
- static char
- hrqerr_messages [][32] =
- {
- "internal error",
- "gethostbyname",
- "unknown host",
- "setreuid",
- "getprotobyname",
- "socket",
- "malloc",
- "setitimer",
- };
-
-
- char *
- hrqerr( int status )
- {
- return hrqerr_messages [status - HRQERR_FIRST_IN_LIST];
- }
-
-